﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

using org.apache.mahout.cf.taste;
using org.apache.mahout.cf.taste.model;
using org.apache.mahout.cf.taste.impl.model.file;
using org.apache.mahout.cf.taste.impl.eval;
using org.apache.mahout.cf.taste.eval;
using org.apache.mahout.cf.taste.impl.similarity;
using org.apache.mahout.cf.taste.impl.neighborhood;
using org.apache.mahout.cf.taste.impl.recommender;
using org.apache.mahout.cf.taste.impl.recommender.svd;
using org.apache.mahout.cf.taste.impl.model;
using org.apache.mahout.cf.taste.recommender;

namespace NReco.Recommender.Examples.GroupLensMovie
{
    public class Program
    {
		static int Main(string[] args) {
			var json = new JavaScriptSerializer();
			if (args.Length == 0) {
				Console.WriteLine("Expected command line parameter (json list of film preferred IDs)");
				return 1;
			}

			var preferredFilmIds = json.Deserialize<IList<int>>(args[0]);

			DataModel model = new FileDataModel("ratings.dat",false, FileDataModel.DEFAULT_MIN_RELOAD_INTERVAL_MS, false);

			RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();

			//Console.WriteLine(evaluator.evaluate(new UserBasedRecommenderBuilder(), null, model, 0.7, 1.0));
			//Console.WriteLine(evaluator.evaluate(new ItemBasedRecommenderBuilder(), null, model, 0.7, 1.0));

			var plusAnonymModel = new PlusAnonymousUserDataModel(model);
			var prefArr = new GenericUserPreferenceArray(preferredFilmIds.Count);
			prefArr.setUserID(0, PlusAnonymousUserDataModel.TEMP_USER_ID);
			
			for (int i=0; i<preferredFilmIds.Count; i++) {
				prefArr.setItemID(i, preferredFilmIds[i]); 
				prefArr.setValue(i, 5); // lets assume max rating
			}
			plusAnonymModel.setTempPrefs(prefArr);

			var recommender = new UserBasedRecommenderBuilder(preferredFilmIds.Count).buildRecommender(plusAnonymModel);

			var st = new System.Diagnostics.Stopwatch();
			st.Start();
			var recommendedItems = recommender.recommend( PlusAnonymousUserDataModel.TEMP_USER_ID, 5, null); //
			st.Stop();

			//Console.WriteLine("Recommended {0} films in {1}ms", recommendedItems.Count, st.ElapsedMilliseconds);

			Console.WriteLine( json.Serialize( recommendedItems.Select( ri => new Dictionary<string,object>() {
				{"film_id", ri.getItemID() },
				{"rating", ri.getValue() },
			}).ToArray() ) );

			return 0;
		}


		public class UserBasedRecommenderBuilder : RecommenderBuilder {

			int numPreferred;

			public UserBasedRecommenderBuilder(int numPreferred) {
				this.numPreferred = numPreferred;
			}

			public org.apache.mahout.cf.taste.recommender.Recommender buildRecommender(DataModel dataModel) {
				var similarity = new LogLikelihoodSimilarity(dataModel); //LogLikelihoodSimilarity(dataModel);
				var neighborhood = new NearestNUserNeighborhood( 10, similarity, dataModel);
				//return new SVDRecommender(dataModel, new ALSWRFactorizer(dataModel, 100, 0.05, 7), new FilePersistenceStrategy("svd_alswr.dat") );
				return new GenericUserBasedRecommender(dataModel, neighborhood, similarity);
			
			}
		}


    }
}
